//! 设备地址

use core::convert::{TryFrom, TryInto};
use core::fmt;
use heapless::consts::*;
use heapless::Vec;

/// 上级父设备地址
pub const ID_PARENT: Id = Id {
    len: 3,
    buf: [
        0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00,
    ],
};
/// 下级子设备地址
pub const ID_ALL: Id = Id {
    len: 3,
    buf: [
        0xF1, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00,
    ],
};
/// 地址最大长度
pub(crate) const ID_LEN: usize = 17;
/// 地址长度增量
pub(crate) const OFFSET: u8 = (ID_LEN - 0x0F) as u8;

/// 全球唯一ID
pub struct UniqueId {
    product: Vec<u8, U7>,
    sn: Vec<u8, U8>,
}
impl UniqueId {
    pub fn new(product: &[u8], sn: &[u8]) -> Self {
        let mut i_p = 0;
        while i_p < product.len() && product[i_p] == 0 {
            i_p += 1;
        }
        let mut i_s = 0;
        while i_s < sn.len() && sn[i_s] == 0 {
            i_s += 1;
        }
        return UniqueId {
            product: Vec::from_slice(&product[i_p..]).unwrap(),
            sn: Vec::from_slice(&sn[i_s..]).unwrap(),
        };
    }
}
impl From<&UniqueId> for Id {
    fn from(id: &UniqueId) -> Self {
        let mut buf: [u8; ID_LEN] = [0; ID_LEN];
        let product_len = id.product.len();
        let sn_len = id.sn.len();
        buf[0] = 0x80 | (product_len + sn_len) as u8;
        buf[1] = ((sn_len << 4) | product_len) as u8;
        buf[2..2 + product_len].copy_from_slice(&id.product);
        buf[2 + product_len..2 + product_len + sn_len].copy_from_slice(&id.sn);
        Id {
            len: 2 + product_len + sn_len,
            buf: buf,
        }
    }
}
impl TryFrom<&Id> for UniqueId {
    type Error = &'static str;
    fn try_from(id: &Id) -> Result<Self, Self::Error> {
        if id.kind() != IdKind::Unique {
            return Err("error kind.");
        }
        let product_len = id.buf[1] & 0x0F;
        let sn_len = (id.buf[1] & 0xF0) >> 4;
        if id.len as u8 != 2 + product_len + sn_len || sn_len > 8 {
            return Err("error len.");
        }
        return Ok(UniqueId::new(
            &id.buf[2..2 + product_len as usize],
            &id.buf[2 + product_len as usize..],
        ));
    }
}
/// 私有内网ID
pub struct PrivateId {
    sn: Vec<u8, U15>,
}
impl PrivateId {
    pub fn new(sn: &[u8]) -> Self {
        let mut i_s = 0;
        while sn[i_s] == 0 {
            i_s += 1;
        }
        return PrivateId {
            sn: Vec::from_slice(&sn[i_s..]).unwrap(),
        };
    }
}
impl From<&PrivateId> for Id {
    fn from(id: &PrivateId) -> Self {
        let mut buf: [u8; ID_LEN] = [0; ID_LEN];
        let len = id.sn.len();
        buf[0] = 0x00 | len as u8;
        buf[1] = len as u8;
        buf[2..2 + len].copy_from_slice(&id.sn);
        Id {
            len: 2 + len,
            buf: buf,
        }
    }
}
impl TryFrom<&Id> for PrivateId {
    type Error = &'static str;
    fn try_from(id: &Id) -> Result<Self, Self::Error> {
        if id.kind() != IdKind::Private {
            return Err("error kind.");
        }
        let sn_len = id.buf[1] & 0x0F;
        if id.len as u8 != 2 + sn_len {
            return Err("error len.");
        }
        return Ok(PrivateId::new(&id.buf[2..2 + sn_len as usize]));
    }
}
/// 随机ID
pub struct RandomId {
    sn: Vec<u8, U15>,
}
impl RandomId {
    pub fn new(sn: &[u8]) -> Self {
        let mut i_s = 0;
        while sn[i_s] == 0 {
            i_s += 1;
        }
        return RandomId {
            sn: Vec::from_slice(&sn[i_s..]).unwrap(),
        };
    }
}
impl From<&RandomId> for Id {
    fn from(id: &RandomId) -> Self {
        let mut buf: [u8; ID_LEN] = [0; ID_LEN];
        let len = id.sn.len();
        buf[0] = 0x40 | len as u8;
        buf[1] = len as u8;
        buf[2..2 + len].copy_from_slice(&id.sn);
        Id {
            len: 2 + len,
            buf: buf,
        }
    }
}
impl TryFrom<&Id> for RandomId {
    type Error = &'static str;
    fn try_from(id: &Id) -> Result<Self, Self::Error> {
        if id.kind() != IdKind::Random {
            return Err("error kind.");
        }
        let sn_len = id.buf[1] & 0x0F;
        if id.len as u8 != 2 + sn_len {
            return Err("error len.");
        }
        return Ok(RandomId::new(&id.buf[2..2 + sn_len as usize]));
    }
}
/// 内测ID
pub struct TestId {
    sn: [u8; 2],
}
impl TestId {
    pub fn new(sn: &[u8; 2]) -> Self {
        return TestId { sn: sn.clone() };
    }
}
impl From<&TestId> for Id {
    fn from(id: &TestId) -> Self {
        let mut buf: [u8; ID_LEN] = [0; ID_LEN];
        buf[0] = 0xF0 | 2;
        buf[1..1 + 2].copy_from_slice(&id.sn);
        Id {
            len: 1 + 2,
            buf: buf,
        }
    }
}
impl TryFrom<&Id> for TestId {
    type Error = &'static str;
    fn try_from(id: &Id) -> Result<Self, Self::Error> {
        if id.kind() != IdKind::Test {
            return Err("error kind.");
        }
        if id.len as u8 != 3 {
            return Err("error len.");
        }
        return Ok(TestId::new(&id.buf[1..3].try_into().unwrap()));
    }
}

/// unmp设备地址类型
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum IdKind {
    Unique,
    Private,
    Random,
    Test,
    Unknow,
}
/// unmp设备地址
#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct Id {
    len: usize,
    buf: [u8; ID_LEN],
}
impl Id {
    pub const fn new() -> Self {
        Id {
            len: 0,
            buf: [0; ID_LEN],
        }
    }
    pub fn kind(&self) -> IdKind {
        if self.len as u8 != ((self.buf[0] & 0x0F) + OFFSET) {
            return IdKind::Unknow;
        }
        match self.buf[0] & 0xF0 {
            0x80 => IdKind::Unique,
            0x00 => IdKind::Private,
            0x40 => IdKind::Random,
            0xF0 => IdKind::Test,
            _ => IdKind::Unknow,
        }
    }
}
impl fmt::Debug for Id {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Id{:?}({:02X?})", self.kind(), &self.buf[..self.len])
    }
}
impl From<&[u8]> for Id {
    fn from(id: &[u8]) -> Self {
        let mut buf: [u8; ID_LEN] = [0; ID_LEN];
        let len = id.len();
        buf[0..len].copy_from_slice(id);
        Id { len, buf }
    }
}
impl core::ops::Deref for Id {
    type Target = [u8];
    fn deref(&self) -> &Self::Target {
        &self.buf[..self.len]
    }
}
